import QtQuick 2.15
import QmlGraphics 1.0

QmlGraphicsViewPreview {
    id: preview
    clip: true

    property var overlay: overlayItem
    property color viewWindowColor: Qt.rgba(1, 0, 0, 1)
    property alias backgroundPreviewVisible: sourcePreview.visible
    property rect initialRect: Qt.rect(-1280 / 2., -720 / 2.,
                                         1280, 720)
    onSourceChanged: {
        if (source &&
            source.scene) {
            resetVisibleWindow()
            source.scene.onWidthChanged.connect(updatePreview)
            source.scene.onHeightChanged.connect(updatePreview)
            source.scene.onScaleChanged.connect(updatePreview)
            source.scene.onChildrenRectChanged.connect(updatePreview)
            source.sceneItemModified.connect(updatePreview)
            sourcePreview.sourceItem = source.scene
        } else
            sourcePreview.sourceItem = undefined
        updatePreview()
        updateVisibleWindow()
    }

    ShaderEffectSource {
        id: sourcePreview
        anchors.fill: parent
        anchors.margins: 0
        live: true
        recursive: false
        textureSize: Qt.size(width, height)
    }

    function updatePreview() {
        if (!source)
            return
        const r = computeSourceRect()
        if (r &&
            r.width > 0. &&
            r.height > 0) {
            sourcePreview.sourceRect = r
            viewWindow.visible = true
            updateVisibleWindow(r)
        } else
            viewWindow.visible = false
    }

    function computeSourceRect(rect) {
        if (!source)
            return undefined
        if (!preview.source ||
            !preview.source.scene ||
            sourcePreview.sourceItem !== preview.source.scene)
            return undefined
        let cr = preview.source.scene.childrenRect
        let r = preview.rectUnion(cr, preview.initialRect)
        return r
    }

    function resetVisibleWindow() {
        const border = viewWindow.border.width
        const border2 = border * 2
        viewWindow.x = border
        viewWindow.y = border
        viewWindow.width = preview.width - border2
        viewWindow.height = preview.height - border2
    }

    function updateVisibleWindow(r) {
        if (!preview)
            return
        if (!source) {
            preview.resetVisibleWindow()
            return
        }
        var containerItem = source.scene
        if (!containerItem) {
            preview.resetVisibleWindow()
            return
        }
        if (!r)
            return

        const border = viewWindow.border.width
        const border2 = border * 2.

        const viewR = preview.source.mapToItem(preview.source.scene,
                                               Qt.rect(0, 0,
                                                       preview.source.width,
                                                       preview.source.height))
        var previewXRatio = preview.width / r.width
        var previewYRatio = preview.height / r.height

        viewWindow.visible = true
        viewWindow.x = (previewXRatio * (viewR.x - r.x)) + border
        viewWindow.y = (previewYRatio * (viewR.y - r.y)) + border

        viewWindow.width = Math.max(12, (previewXRatio * viewR.width) - border2)
        viewWindow.height = Math.max(9, (previewYRatio * viewR.height) - border2)

        visibleWindowChanged(Qt.rect(viewWindow.x / preview.width,
                                  viewWindow.y / preview.height,
                                  viewWindow.width / preview.width,
                                  viewWindow.height / preview.height),
                             source.zoom);
    }

    function    mapFromPreview(p) {
        if (!p)
            return;

        let r = sourcePreview.sourceRect
        var previewXRatio = r.width / preview.width
        var previewYRatio = r.height / preview.height
        let sourceP = Qt.point((p.x * previewXRatio) + r.x,
                               (p.y * previewYRatio) + r.y)
        return sourceP
    }

    Item {
        id: overlayItem
        anchors.fill: parent; anchors.margins: 0
    }
    Rectangle {
        id: viewWindow
        z: 1
        color: Qt.rgba(0, 0, 0, 0)
        smooth: true
        antialiasing: true
        border.color: viewWindowColor
        border.width: 2
        onXChanged: viewWindowDragged()
        onYChanged: viewWindowDragged()
        function viewWindowDragged() {
            if (source &&
                (viewWindowController.pressedButtons & Qt.LeftButton ||
                 viewWindowController.active)) {

                let sceneP = mapFromPreview(Qt.point(viewWindow.x, viewWindow.y))
                source.moveTo(sceneP)
            }
        }
        MouseArea {
            id: viewWindowController
            anchors.fill: parent
            drag.target: viewWindow
            drag.threshold: 1.
            drag.minimumX: 0
            drag.minimumY: 0
            drag.maximumX: Math.max(0, preview.width - viewWindow.width)
            drag.maximumY: Math.max(0, preview.height - viewWindow.height)
            acceptedButtons: Qt.LeftButton
            enabled: true
            cursorShape: Qt.SizeAllCursor

            Timer {
                id: viewWindowTimer
                interval: 100
                running: false
                property point p: Qt.point(0, 0)
                onTriggered: {
                    let sceneP = mapFromPreview(Qt.point(p.x, p.y))
                    source.centerOnPosition(sceneP)
                    updatePreview()
                }
            }
            onClicked: {
                let p = mapToItem(preview, Qt.point(mouse.x, mouse.y))
                viewWindowTimer.p = p
                viewWindowTimer.start()
                mouse.accepted = true
            }
            onDoubleClicked: {
                viewWindowTimer.stop()
                let p = mapToItem(preview, Qt.point(mouse.x, mouse.y))
                let sceneP = mapFromPreview(p)
                source.centerOnPosition(sceneP)
                source.zoom = 1.0
                mouse.accepted = true
                updatePreview()
            }
        }
    }
    MouseArea {
        id: navigationController
        anchors.fill: parent
        z: 0
        acceptedButtons: Qt.LeftButton
        enabled: true
        cursorShape: Qt.CrossCursor
        Timer {
            id: timer
            interval: 100
            running: false
            property point p: Qt.point(0, 0)
            onTriggered: {
                let sceneP = mapFromPreview(Qt.point(p.x, p.y))
                source.centerOnPosition(sceneP)
                updatePreview()
            }
        }
        onClicked: {
            timer.p = Qt.point(mouse.x, mouse.y)
            timer.start()
            mouse.accepted = true
        }
        onDoubleClicked: {
            timer.stop()
            let sceneP = mapFromPreview(Qt.point(mouse.x, mouse.y))
            source.centerOnPosition(sceneP)
            source.zoom = 1.0
            mouse.accepted = true
            updatePreview()
        }
    }
}
